package org.streets.wicket.ioc;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.ioc.annotations.InjectService;
import org.apache.wicket.Component;
import org.apache.wicket.WicketRuntimeException;
import org.apache.wicket.application.IComponentInstantiationListener;

import org.streets.context.HiveRegistry;
/**
 * Component Injector with tapestry-ioc for wicket page class
 * Now, just support Field inject
 * @author dzb
 */
public class HiveComponentInjector implements IComponentInstantiationListener {
	
	private final HiveRegistry registry;
	
	private final Map<Class< ? >, Boolean> classToDoInject = new ConcurrentHashMap<Class< ? >, Boolean>();
	
	public HiveComponentInjector(HiveRegistry registry) {
		
		this.registry = registry;
		
	}


	public void onInstantiation(Component component) {
		
		inject(component);
		
	}
	
	public void inject(Object object) {
		
		Class< ? > current = object.getClass();
		
		Boolean doInject = classToDoInject.get(current);
		if (doInject != null && !doInject.booleanValue())
		{
			return;
		}
		
		boolean actualDoInject = false;
		
		do {			
			Field[] currentFields = current.getDeclaredFields();			
			for (final Field field : currentFields)				
			{
				if (!Modifier.isStatic(field.getModifiers()) &&	field.getAnnotations().length > 0) 
				{
					try
					{
						Class<?> type = field.getType();
						Inject annotationInject = field.getAnnotation(Inject.class);
						if (annotationInject != null) {
							actualDoInject = true;				
							Object v = registry.service(type);
							if (!field.isAccessible()) {
								field.setAccessible(true);
							}
							field.set(object, v);							
							continue;
						}
						InjectService annotationInjectService = field.getAnnotation(InjectService.class);
						if (annotationInjectService != null) {
							actualDoInject = true;
							Object v = registry.service(annotationInjectService.value(), type);
							field.set(object, v);
							if (!field.isAccessible()) {
								field.setAccessible(true);
							}
							continue;
						}
						

					}
					catch (IllegalAccessException e)
					{
						throw new WicketRuntimeException("Error Hive-injecting field " +
								field.getName() + " in " + object, e);
					}
				}
			}
			current = current.getSuperclass();
		} 
		while (current != null && current != Object.class);
		
		if (doInject == null) {
			classToDoInject.put(object.getClass(), new Boolean(actualDoInject));
		}
	}
}
